#include <iostream>

#include "CSignal.h"

using namespace std;

int serial_wait(pid_t pid, CSignalMask *child_signal)
{
	if(CSignal::instance()->waitinfo(child_signal)==SIGRTMIN+1) {
		cerr << "child = " << child_signal->get_wait_pid() << " is exited with user data = " << child_signal->get_wait_value_int() << endl;
	}
	else {
		cerr << "what the heck is wrong pid = " << child_signal->get_wait_pid() << endl;
	}
}

int main(int argc, char **argv)
{
	if(argc<2) {
		cerr << "Usage : " << argv[0] << " 1 or 2" << endl;
		cerr << "\t1\tfirst child 1, next child 2" << endl;
		cerr << "\t2\tfirst child 2, next child 1" << endl;
		exit(-1);
	}

	int first = atoi(argv[1]);

	pid_t pid1 = fork();
	if(pid1==0) { // 1st child
		CSignalMask *parent_signal = new CSignalMask();
		parent_signal->add(SIGRTMIN);
		
		CSignal::instance()->setmask(parent_signal);
		if(CSignal::instance()->waitinfo(parent_signal)==SIGRTMIN) {
			cerr << "parent is started, so child 1 will be started now" << endl;

			// do anything
			system("date");

			union sigval sv;
			sv.sival_int = 1; 

			CSignal::instance()->trigger(parent_signal->get_wait_pid(), SIGRTMIN+1, sv);

			delete parent_signal;
			exit(0);
		}
		else {
			cerr << "received wrong signal" << endl;

			delete parent_signal;
			exit(-1);
		}
	}
	else {
		pid_t pid2 = fork();
		if(pid2==0) { // 2nd child
			CSignalMask *parent_signal = new CSignalMask();
			parent_signal->add(SIGRTMIN);

			CSignal::instance()->setmask(parent_signal);
			if(CSignal::instance()->waitinfo(parent_signal)==SIGRTMIN) {
				cerr << "parent is started, so child 2 will be started now" << endl;

				// do anything
				system("date");

				union sigval sv;
				sv.sival_int = 1; 
				CSignal::instance()->trigger(parent_signal->get_wait_pid(), SIGRTMIN+1, sv);

				delete parent_signal;
				exit(0);
			}
			else {
				cerr << "received wrong signal" << endl;

				delete parent_signal;
				exit(-1);
			}
		}
		else { // parent
			CSignalMask *child_signal = new CSignalMask();
			child_signal->add(SIGRTMIN+1);

			// blocking singal mask
			CSignal::instance()->block(child_signal);

			if(first==1) {
				union sigval sv;
				sv.sival_int = 1; 

				CSignal::instance()->trigger(pid1, SIGRTMIN, sv);
				serial_wait(pid1, child_signal);

				CSignal::instance()->trigger(pid2, SIGRTMIN, sv);
				serial_wait(pid2, child_signal);
			}
			else if(first==2) {
				union sigval sv;
				sv.sival_int = 1; 

				CSignal::instance()->trigger(pid2, SIGRTMIN, sv);
				serial_wait(pid2, child_signal);

				CSignal::instance()->trigger(pid1, SIGRTMIN, sv);
				serial_wait(pid1, child_signal);
			}

			delete child_signal;
		}
	}
}
